Skip to content

feat(pt): support shared_dict in linear energy model#5548

Open
njzjz-bot wants to merge 4 commits into
deepmodeling:masterfrom
njzjz-bothub:fix/linear-shared-dict
Open

feat(pt): support shared_dict in linear energy model#5548
njzjz-bot wants to merge 4 commits into
deepmodeling:masterfrom
njzjz-bothub:fix/linear-shared-dict

Conversation

@njzjz-bot

@njzjz-bot njzjz-bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add shared_dict support to the PyTorch linear_ener model config, reusing the multi-task shared-parameter preprocessor.
  • Share descriptor/fitting parameters among linear sub-models with the same shared-link semantics as multi-task training.
  • Preserve shared references through update_sel, including configs where type_map only lives in shared_dict.
  • Add unit coverage for shared descriptor/type_map references and top-level type_map plus shared descriptors.

Closes #4412.
Supersedes/continues #4933.

Tests

  • uvx ruff check deepmd/pt/model/model/dp_linear_model.py deepmd/pt/model/model/__init__.py deepmd/pt/utils/multi_task.py deepmd/utils/argcheck.py source/tests/pt/model/test_linear_model_shared_dict.py
  • uvx ruff format deepmd/pt/model/model/dp_linear_model.py deepmd/pt/model/model/__init__.py deepmd/pt/utils/multi_task.py deepmd/utils/argcheck.py source/tests/pt/model/test_linear_model_shared_dict.py
  • python3 -m py_compile deepmd/pt/model/model/dp_linear_model.py deepmd/pt/model/model/__init__.py deepmd/pt/utils/multi_task.py deepmd/utils/argcheck.py source/tests/pt/model/test_linear_model_shared_dict.py

Note: local pytest -q source/tests/pt/model/test_linear_model_shared_dict.py could not run in this worktree because the compiled deepmd.lib extension is unavailable in the local environment.

Authored by OpenClaw (model: custom-chat-jinzhezeng-group/gpt-5.5)

Summary by CodeRabbit

  • New Features
    • Added shared_dict support for linear_ener models, enabling parameter sharing across atomic sub-models (including descriptor and fitting-network sharing).
    • Extended linear_ener selection updates to round-trip shared_dict configurations while preserving shared descriptor references.
  • Bug Fixes
    • Improved validation for type_map resolution under shared configurations (enforcing consistent sub-model type_map when needed).
  • Tests
    • Added/expanded tests for shared type_map, shared_links population, hybrid descriptors, and update_sel round-trip behavior.

Authored by OpenClaw (model: custom-chat-jinzhezeng-group/gpt-5.5)
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5c12880b-b4a8-4e35-9183-2a22d2b5b35c

📥 Commits

Reviewing files that changed from the base of the PR and between 7a7cd38 and cc6fa8c.

📒 Files selected for processing (2)
  • deepmd/pt/model/model/dp_linear_model.py
  • source/tests/pt/model/test_linear_model_shared_dict.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • deepmd/pt/model/model/dp_linear_model.py

📝 Walkthrough

Walkthrough

Adds shared_dict support to LinearEnergyModel, enabling sub-models in a linear_ener config to share descriptors and parameters. preprocess_shared_params gains a require_shared_type_map flag for relaxed type_map validation. get_linear_model is extended to process shared_dict, build per-sub-model configs, and wire share_params. LinearEnergyModel.share_params and update_sel are implemented/extended for this flow; the linear_ener schema registers the new shared_dict field.

Changes

shared_dict parameter sharing for LinearEnergyModel

Layer / File(s) Summary
Relaxed type_map validation in preprocess_shared_params
deepmd/pt/utils/multi_task.py
Adds require_shared_type_map parameter (default True) to allow zero-or-one type_map keys for non-multi-task usage instead of enforcing exactly one; reformats hybrid item detection and applies conditional assertion on type_map_keys length.
Schema registration for shared_dict in linear_ener
deepmd/utils/argcheck.py
Adds doc_shared_dict documentation string and optional shared_dict dictionary field (default {}) to the linear_ener model configuration schema.
shared_dict wiring in get_linear_model
deepmd/pt/model/model/__init__.py
Imports preprocess_shared_params; extends get_linear_model to build a shared_config, call preprocess_shared_params with relaxed validation when shared_dict is present, derive per-sub-model ntypes from type_map length and type_map itself, construct atomic models with deep-copied sub-model type_maps, and invoke model.share_params with the resolved shared_links.
LinearEnergyModel.share_params implementation
deepmd/pt/model/model/dp_linear_model.py
Adds logging, deepcopy imports and preprocess_shared_params import plus module logger; implements share_params method to iterate shared_links, enforce non-decreasing shared_level, resolve sub-models and descriptor classes (including hybrid list indexing), compute per-link model_prob from model_key_prob_map, delegate to underlying share_params, and emit warning logs for each operation.
LinearEnergyModel.update_sel extension
deepmd/pt/model/model/dp_linear_model.py
Rewrites update_sel classmethod to deep-copy and preprocess sub-model list via preprocess_shared_params when shared_dict is present, compute selection updates per non-tab_file sub-model while tracking min_nbor_dist, then reconstruct return payload restoring original models and updating ret_jdata["shared_dict"] descriptors for both plain-string and hybrid dict descriptor reference formats.
Tests for shared_dict linear model
source/tests/pt/model/test_linear_model_shared_dict.py
Adds TestLinearEnergySharedDict with helper assert_dpa1_descriptor_shared and comprehensive tests: one using type_map_all in shared_dict, one using top-level type_map with shared descriptor, one validating hybrid descriptors with shared list elements, two testing update_sel round-trip with mocked neighbor stats (one with inline and shared descriptors mixed, one with string and inline descriptors), one validating shared fitting network identity, and two negative tests ensuring type_map presence and consistency requirements; all assert resolved types, shared_links presence, and module identity across sub-models.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • iProzd
  • njzjz
  • wanghan-iapcm
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(pt): support shared_dict in linear energy model' clearly and concisely summarizes the main change: adding shared_dict support to PyTorch linear energy models.
Linked Issues check ✅ Passed The PR implementation fully addresses issue #4412 by adding shared_dict support to the linear energy model with shared descriptor and type_map references, matching the requested feature and example configuration structure.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing shared_dict support for linear energy models: configuration schema updates, parameter sharing logic, type_map handling, and comprehensive test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
source/tests/pt/model/test_linear_model_shared_dict.py (1)

9-101: 🏗️ Heavy lift

Add coverage for the unexercised shared_dict branches.

These tests only cover descriptor sharing through get_model. Please add focused regressions for the new update_sel shared_dict round-trip and a non-descriptor shared link, so the descriptor-restoration logic and the Line 108-Line 144 share_params branch cannot regress silently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/pt/model/test_linear_model_shared_dict.py` around lines 9 - 101,
Add two new test methods to the TestLinearEnergySharedDict class to improve
coverage. First, create a test that exercises the update_sel shared_dict
round-trip functionality to ensure descriptor restoration logic works correctly
when sel is modified and restored. Second, create a test that covers a
non-descriptor shared link (not just descriptor sharing) to exercise the
share_params branch and ensure parameter sharing for non-descriptor shared
objects works as expected and cannot regress silently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deepmd/pt/model/model/__init__.py`:
- Around line 177-180: The code at line 177 assumes all sub-models in
model_params["models"] have the same type_map but only validates the first one.
Before copying type_map from models[0], iterate through all models in
model_params["models"] to ensure each one has a type_map and that all type_maps
are identical. If any inconsistency is found (missing type_map or differing
values), raise a ValueError with a descriptive message. Only proceed with
copying from models[0] if all models have consistent type_maps.

In `@deepmd/pt/model/model/dp_linear_model.py`:
- Around line 84-99: Replace the assert statements that validate shared_level
ordering and type matching with explicit exception-based validation. Convert
shared_level_base to int using int() function before comparisons, then introduce
a variable to track the previous_shared_level within the loop iterating over
shared_links items. After extracting shared_level_link, validate that it is
greater than or equal to previous_shared_level (not just shared_level_base) and
raise a ValueError if the ordering constraint is violated. Similarly, replace
the assert for class type validation with an explicit exception raise. Apply
these changes consistently to both code paths where this pattern appears (around
the links iteration and the link_class.share_params call).

---

Nitpick comments:
In `@source/tests/pt/model/test_linear_model_shared_dict.py`:
- Around line 9-101: Add two new test methods to the TestLinearEnergySharedDict
class to improve coverage. First, create a test that exercises the update_sel
shared_dict round-trip functionality to ensure descriptor restoration logic
works correctly when sel is modified and restored. Second, create a test that
covers a non-descriptor shared link (not just descriptor sharing) to exercise
the share_params branch and ensure parameter sharing for non-descriptor shared
objects works as expected and cannot regress silently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5c1b8781-2637-4efc-a3cf-a4fe00c95203

📥 Commits

Reviewing files that changed from the base of the PR and between 4a552e3 and 276ad86.

📒 Files selected for processing (5)
  • deepmd/pt/model/model/__init__.py
  • deepmd/pt/model/model/dp_linear_model.py
  • deepmd/pt/utils/multi_task.py
  • deepmd/utils/argcheck.py
  • source/tests/pt/model/test_linear_model_shared_dict.py

Comment thread deepmd/pt/model/model/__init__.py Outdated
Comment thread deepmd/pt/model/model/dp_linear_model.py Outdated
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.56198% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.20%. Comparing base (4a552e3) to head (cc6fa8c).
⚠️ Report is 10 commits behind head on master.

Files with missing lines Patch % Lines
deepmd/pt/model/model/dp_linear_model.py 90.32% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5548      +/-   ##
==========================================
- Coverage   82.23%   82.20%   -0.03%     
==========================================
  Files         894      898       +4     
  Lines      102002   103689    +1687     
  Branches     4276     4432     +156     
==========================================
+ Hits        83877    85236    +1359     
- Misses      16823    17059     +236     
- Partials     1302     1394      +92     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Share linear model parameters in resume mode during construction so descriptor statistics are not required before training computes them. Also validate linear shared links and inferred type maps explicitly.

Authored by OpenClaw (model: custom-chat-jinzhezeng-group/gpt-5.5)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deepmd/pt/model/model/__init__.py`:
- Around line 185-190: The ValueError raised when sub_model_params type_map
values don't match is missing the model index information, making it difficult
to identify which sub-model has the mismatch. Include the idx variable (which is
already captured in the loop) in the error message string to clearly indicate
which sub-model has the mismatched type_map value. Update the error message in
the ValueError to include the model index along with the existing description.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cd4f9bab-18aa-49cb-80c2-5f5a57d58352

📥 Commits

Reviewing files that changed from the base of the PR and between 276ad86 and 9127c12.

📒 Files selected for processing (2)
  • deepmd/pt/model/model/__init__.py
  • deepmd/pt/model/model/dp_linear_model.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • deepmd/pt/model/model/dp_linear_model.py

Comment thread deepmd/pt/model/model/__init__.py
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

An unexpected error occurred while generating fixes: Not Found - https://docs.github.com/rest/git/refs#get-a-reference

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
source/tests/pt/model/test_linear_model_shared_dict.py (1)

18-18: ⚡ Quick win

Consider a more explicit assertion.

Using assertTrue on a dict checks if it's non-empty, but this intent is not immediately clear. Consider using a more explicit assertion.

✨ More explicit alternative
-        self.assertTrue(descriptor0.se_atten._modules)
+        self.assertGreater(len(descriptor0.se_atten._modules), 0, "Expected se_atten to have modules")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/tests/pt/model/test_linear_model_shared_dict.py` at line 18, Replace
the implicit truthiness check on the dictionary descriptor0.se_atten._modules
with a more explicit assertion that clearly communicates the intent to verify
the dictionary is non-empty. Instead of using assertTrue on the dict directly,
use an assertion method like assertGreater with len() to explicitly check the
dictionary length is greater than zero, making the intent immediately clear to
readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@source/tests/pt/model/test_linear_model_shared_dict.py`:
- Line 18: Replace the implicit truthiness check on the dictionary
descriptor0.se_atten._modules with a more explicit assertion that clearly
communicates the intent to verify the dictionary is non-empty. Instead of using
assertTrue on the dict directly, use an assertion method like assertGreater with
len() to explicitly check the dictionary length is greater than zero, making the
intent immediately clear to readers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 87b86aff-8314-4e17-aeb1-4f0e2b935577

📥 Commits

Reviewing files that changed from the base of the PR and between 9127c12 and 7a7cd38.

📒 Files selected for processing (2)
  • deepmd/pt/model/model/__init__.py
  • source/tests/pt/model/test_linear_model_shared_dict.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • deepmd/pt/model/model/init.py

@njzjz njzjz requested review from iProzd and wanghan-iapcm June 19, 2026 14:22
Comment on lines +75 to +77
if "hybrid" in shared_type:
hybrid_index = int(shared_type.split("_")[-1])
return sub_model.descriptor.descriptor_list[hybrid_index]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hybrid-descriptor branch here (descriptor_list[hybrid_index]) is reachable but never exercised. The only test that builds a hybrid descriptor (test_shared_dict_update_sel_round_trip) drives update_sel, not share_params; the three tests that actually call share_params (via get_model) all use a plain dpa1 descriptor and only hit the shared_type == "descriptor" path above. CLAUDE.md: "When adding a new feature or API, provide tests that exercise every reachable code path." Consider a test that shares one component of a hybrid descriptor between two linear sub-models. Non-blocking.

Comment on lines +320 to +339
if isinstance(descriptor_ref, str):
ret_jdata["shared_dict"][get_shared_key(descriptor_ref)] = (
updated_sub_model["descriptor"]
)
elif (
isinstance(descriptor_ref, dict)
and descriptor_ref.get("type") == "hybrid"
):
updated_descriptor = updated_sub_model["descriptor"]
for hybrid_idx, hybrid_ref in enumerate(descriptor_ref["list"]):
if isinstance(hybrid_ref, str):
ret_jdata["shared_dict"][get_shared_key(hybrid_ref)] = (
updated_descriptor["list"][hybrid_idx]
)
else:
ret_jdata["models"][idx]["descriptor"]["list"][hybrid_idx] = (
updated_descriptor["list"][hybrid_idx]
)
else:
ret_jdata["models"][idx]["descriptor"] = updated_sub_model["descriptor"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The descriptor write-back has three branches: a string ref (isinstance(descriptor_ref, str), L320), a hybrid dict (L324), and an inline dict (the final else, L339). test_shared_dict_update_sel_round_trip only uses a hybrid descriptor, so only the middle branch runs; the string-ref and inline-dict branches are untested. CLAUDE.md: "UTs should cover all code paths, including both branches of boolean conditions." Non-blocking.

Comment on lines +179 to +189
if "type_map" not in sub_model_params:
raise ValueError(
f"Linear sub-model {idx} must define type_map when "
"linear_ener has no top-level type_map."
)
first_type_map = model_params["models"][0]["type_map"]
for idx, sub_model_params in enumerate(model_params["models"][1:], start=1):
if sub_model_params["type_map"] != first_type_map:
raise ValueError(
f"Linear sub-model {idx} type_map differs from sub-model 0. "
"All type_map values must be identical when linear_ener "

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new type_map validation raises in two cases — a sub-model missing type_map (L180-182) and a sub-model whose type_map differs from sub-model 0 (L186-189) — but neither raise is covered. The tests only hit the happy path where all sub-models agree. CLAUDE.md: "When adding a new feature or API, provide tests that exercise every reachable code path." Consider two assertRaises cases. Non-blocking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Use shared_dict for linear model

3 participants